
/*
 *  Copyright t lefering, David Given
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  These are the four essential freedoms with GNU GPL software:
 *  1: freedom to run the program, for any purpose
 *  2: freedom to study how the program works, and change it to make it do what you wish
 *  3: freedom to redistribute copies to help your Free Software friends
 *  4: freedom to distribute copies of your modified versions to your Free Software friends
 *   ,           ,
 *  /             \
 * ((__-^^-,-^^-__))
 * `-_---'  `---_-'
 *  `--|o`   'o|--'
 *      \  `  /
 *       ): :(
 *       :o_o:
 *        "-"
 */

#include "globals.h"

/* line in src, where current instruction is compiled, printed at a assert */
int cur_insn_line = 0;

unsigned int unique = 0;
FILE *outputstream = NULL;
struct symbol_list *all_syms = NULL;

const struct codegenerator *cg = NULL;

static void sparse_output_bb(struct basic_block *bb, unsigned long generation)
{
	struct instruction *insn = NULL;

	bb->generation = generation;
	printf("%s(): label = \"%s\"\n", __func__, show_label(bb));

	FOR_EACH_PTR(bb->insns, insn) {
		if (!insn->bb)
			continue;
		printf("%s():\t%s\n", __func__, show_instruction(insn));
	}
	END_FOR_EACH_PTR(insn);

	printf("\n");
	return;
}

static void sparse_output_fn(struct entrypoint *ep)
{
	struct basic_block *bb = NULL;
	unsigned long generation = ++bb_generation;
	struct symbol *sym = ep->name;
	const char *name = show_ident(sym->ident);

	if (sym->ctype.modifiers & MOD_STATIC) {
		printf("%s(): static \"%s\"\n", __func__, name);
	} else {
		printf("%s(): global \"%s\"\n", __func__, name);
	}
	if (0) {
		unssa(ep);
	}

	FOR_EACH_PTR(ep->bbs, bb) {
		if (bb->generation == generation) {
			continue;
		}
		sparse_output_bb(bb, generation);
	}
	END_FOR_EACH_PTR(bb);
	return;
}

/*
 * Symbol type printout. The type system is by far the most
 * complicated part of C - everything else is trivial.
 */
static const char *show_modifiers(unsigned long mod, int term)
{
	static char buffer[100];
	int len = 0;
	int i = 0;
	struct mod_name {
		unsigned long mod;
		const char *name;
	} *m;

	static struct mod_name mod_names[] = {
		{ MOD_AUTO, "auto" },
		{ MOD_EXTERN, "extern" },
		{ MOD_REGISTER, "register" },
		{ MOD_STATIC, "static" },
		{ MOD_INLINE, "inline" },
		{ MOD_CONST, "const" },
		{ MOD_RESTRICT, "restrict" },
		{ MOD_VOLATILE, "volatile" },
		{ MOD_ADDRESSABLE, "[addressable]" },
		{ MOD_ASSIGNED, "[assigned]" },
		{ MOD_ATOMIC, "[atomic]" },
		{ MOD_BITWISE, "[bitwise]" },
		{ MOD_EXPLICITLY_SIGNED, "[explicitly-signed]" },
		{ MOD_GNU_INLINE, "[gnu_inline]" },
		{ MOD_NOCAST, "[nocast]" },
		{ MOD_NODEREF, "[noderef]" },
		{ MOD_NORETURN, "[noreturn]" },
		{ MOD_PURE, "[pure]" },
		{ MOD_SAFE, "[safe]" },
		{ MOD_SIGNED, "[signed]" },
		{ MOD_TLS, "[tls]" },
		{ MOD_TOPLEVEL, "[toplevel]" },
		{ MOD_UNSIGNED, "[unsigned]" },
		{ MOD_UNUSED, "[unused]" },
		{ MOD_USERTYPE, "[usertype]" },
	};

	for (i = 0; i < ARRAY_SIZE(mod_names); i++) {
		m = mod_names + i;
		if (mod & m->mod) {
			char c;
			const char *name = m->name;
			while ((c = *name++) != '\0' && len + 2 < sizeof buffer) {
				buffer[len++] = c;
			}
			buffer[len++] = ' ';
		}
	}
	if (len && !term)	// strip the trailing space
	{
		--len;
	}
	buffer[len] = 0;
	return buffer;
}

static void sparse_output_data(struct symbol *sym)
{

	printf("%s(): symbol = \"%s\"\n", __func__, show_ident(sym->ident));
	printf("%s(): type   = %d \"%s\"\n", __func__, sym->ctype.base_type->type, show_typename(sym));
	printf("%s(): modif  = %lx \"%s\"\n", __func__, sym->ctype.modifiers, show_modifiers(sym->ctype.modifiers, 0));

	return;
}

static void sparse_compile(struct symbol_list *list)
{
	struct symbol *sym = NULL;
	struct entrypoint *ep = NULL;
	FOR_EACH_PTR(list, sym) {
		expand_symbol(sym);
		ep = linearize_symbol(sym);
		if (ep) {
			sparse_output_fn(ep);
		} else {
			sparse_output_data(sym);
		}
	}
	END_FOR_EACH_PTR(sym);

	fflush(stdout);

	return;
}

static void init_sizes(void)
{
	/* We say everything is 32 bits wide because that tells sparse how
	 * much precision an int can store for things like bitfields.
	 */
	bits_in_char = 32;
	max_alignment = bits_in_char;

	bits_in_bool = 1;
	bits_in_short = bits_in_char;
	bits_in_int = bits_in_char;
	bits_in_long = bits_in_char;
	bits_in_longlong = bits_in_char;

	max_int_alignment = 1;

	/*
	 * Floating point data types
	 */
	bits_in_float = bits_in_char;
	bits_in_double = bits_in_char;
	bits_in_longdouble = bits_in_char;

	max_fp_alignment = 1;

	/*
	 * Pointer data type; these are now stored unpacked, so they're twice
	 * as big.
	 */
#warning "32bit here"
	if (0) {		/* orig */
		bits_in_pointer = bits_in_char * 2;
	} else {
		/* set as 32bits machine */
		bits_in_pointer = bits_in_char;
	}
	pointer_alignment = 1;

	/*
	 * Enum data types
	 */
	bits_in_enum = bits_in_char;
	enum_alignment = 1;

	return;
}

int main(int argc, char *argv[])
{
	struct string_list *filelist = NULL;
	char *file = NULL;
	struct symbol_list *fsyms = NULL;

	/* show more info, values are 0,1,2,3 */
	verbose = 0;

	if (1) {
		cg = &cg_javascript;
	} else {
		cg = &cg_java;
	}

	outputstream = fopen("0output.js", "w");

	init_sizes();
	init_register_allocator();

	fsyms = sparse_initialize(argc, argv, &filelist);
	concat_symbol_list(fsyms, &all_syms);

	zsetbuffer(ZBUFFER_HEADER);

	cg->prologue();

	FOR_EACH_PTR(filelist, file) {
		cg->comment("sparsegen is now running sparse to compile file %s\n", file);
		fsyms = sparse(file);
		concat_symbol_list(fsyms, &all_syms);

		if (0 /* option to dump the parsed data */ ) {
			sparse_compile(fsyms);
		}

		cg->comment("sparsegen finished compiling file %s\n", file);
	}
	END_FOR_EACH_PTR(file);

	if (has_error) {
		printf("%s(): sourcecode has errors\n", __func__);
		return (0);
	}

	compile_symbol_list(all_syms);

	zsetbuffer(ZBUFFER_HEADER);
	zflush(ZBUFFER_STDOUT);
	zprintf("\n");

	zsetbuffer(ZBUFFER_CODE);
	zflush(ZBUFFER_STDOUT);
	zprintf("\n");

	emit_initializer();

	cg->epilogue();

	/* generate graph output with the basic blocks for every function() */
	graph();

	fclose(outputstream);

	return (0);
}

/* end */
